package com.disgruntledbots;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;

import org.json.JSONException;
import org.json.JSONObject;

import android.os.AsyncTask;
import android.util.Log;

public class ClientConnection
{

	public boolean isConnected;
	public boolean hasStreams;
	public Socket socket;
	public String gameID;
	public boolean hasTurn;
	
	public int gameId;
	public int playerNum;
	int serverPort;
	String ip;
	
	DownloadRunnable listener;
	Thread listenerThread;
	
	BufferedReader input;
	PrintWriter output;
	String sentMessage;
	
	JSONObject message;
	
	class UploadRunnable implements Runnable
	{
		String message;
		public UploadRunnable(String message)
		{
			this.message = message;
		}
		public void run()
		{
			if(socket.isConnected()){
				output.println(this.message);
				output.flush();

				Log.i("UploadRunnable", "Message Uploaded");
			}else{
				Log.e("UploadRunnable", "No Connection");
			}
		}
	}
	
	class DownloadRunnable implements Runnable
	{
		private String message;
		private boolean receivedMessage;
		
		public DownloadRunnable()
		{
			receivedMessage = false;
		}
		
		public void run()
		{
			while(socket.isConnected())
			{
				try {
						message = input.readLine();
						if(message != null){
							Log.i("DownloadRunnable", "Input not null");
							receivedMessage = true;
							ClientConnection.this.receivedMessageToJSON();
							receivedMessage = false;
							message = null;
							break;
						}
				} catch (IOException e) {
					// TODO Auto-generated catch block
					Log.e("Reading From Server", e.getMessage());
				}
			}
		}
		
		public boolean hasMessage()
		{
			return receivedMessage;
		}
		
		public String getMessage()
		{
			receivedMessage = false;
			return message;
		}
	}
	
	class ConnectRunnable implements Runnable
	{
		String ip;
		int serverPort;
		public ConnectRunnable(String ip, int serverPort)
		{
			this.ip = ip;
			this.serverPort = serverPort;
		}
		
		@Override
		public void run() {
			try {
				socket = new Socket(this.ip, this.serverPort);
				isConnected = true;
				Log.i("ClientConnect: ","Socket Initialized");
			} catch (UnknownHostException e) {
				isConnected = false;
				Log.e("Initial Connection Unknwon",e.getMessage());
			} catch (IOException e) {
				isConnected = false;
				Log.e("Initial Connection IO", e.getMessage());
			}
			
		}
	}
	
	public  ClientConnection(int serverPort, String ip)
	{
		ClientConnection.ConnectRunnable connect = new ConnectRunnable(ip, serverPort);
		ClientConnection.UploadRunnable sendMessage;
		Thread thread;
		socket = null;
		gameID = null;
		gameId = 0;
		playerNum = 0;
		Thread sendMessageThread;
		
		this.serverPort = serverPort;
		this.ip = ip;
		
		thread = new Thread(connect);
		thread.start();
		
		JSONObject json = new JSONObject();
		try {
			json.put("Message", "Initial");
		} catch (JSONException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		
		while(thread.isAlive())
		{
			
		}
		
		if(socket != null && isConnected)
		{
			try {
				setUpStreams();
				hasStreams = true;
				Log.i("ClientConnect: ","Streams Setup");		
				listener = new ClientConnection.DownloadRunnable();
				listenerThread = new Thread(listener);
				
				sendMessage = new ClientConnection.UploadRunnable(json.toString());
				sentMessage = json.toString();
				sendMessageThread = new Thread(sendMessage);
				sendMessageThread.start();
				listenerThread.start();
				while(listenerThread.isAlive()){
				}
				
				if(hasTurn)
				{
					Log.i("ClientConnection", "Message Interpreted");
					gameId = message.getInt("gameId");
					playerNum = message.getInt("Assignment");
					Log.i("ClientConnection", "GameID:" + gameId + " PlayerNum" + playerNum);
					hasTurn = true;
				}else{
					Log.wtf("ClientConnection", "Missed Response");
				}
				
			} catch (IOException e) {
				// TODO Auto-generated catch block
				Log.e("Setup Streams Error", e.getMessage());
				hasStreams = false;
			} catch (JSONException e) {
				// TODO Auto-generated catch block
				Log.e("JSONError", e.getMessage());
			}
		}
	}
	
	public boolean hasTurn()
	{
		return hasTurn;
	}
	
	public JSONObject getMessage()
	{
		hasTurn = false;
		return message;
	}
	
	private void setUpStreams() throws IOException
	{
		input = new BufferedReader(
				new InputStreamReader(socket.getInputStream()));
		output  = new PrintWriter(
				new OutputStreamWriter(socket.getOutputStream()));
	}
	
	private void receivedMessageToJSON()
	{
		if(listener.hasMessage())
		{
			hasTurn = false;
			message = null;
			Log.i("ClientConnection","Json Message Called");
			try {
				message = new JSONObject(listener.getMessage());
				hasTurn = true;
			} catch (JSONException e) {
				// TODO Auto-generated catch block
				Log.e("Recieved Message", "Could Not convert Message", e);
			}	
		}
	}	
	
	public void sendMessage(JSONObject message)
	{
		UploadRunnable upload;
		Thread sendThread;
		try {
			this.setUpStreams();
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			Log.e("ClientConnection", "Send Message, SetupStreams", e1);
		}
		
		try {
			message.put("Message", "Turn");
			upload = new UploadRunnable(message.toString());
			sendThread = new Thread(upload);
			listenerThread = new Thread(new DownloadRunnable());
			sendThread.start();
			listenerThread.start();
		} catch (JSONException e) {
			Log.e("ClientConncetion", "Send Message", e);
		}
	}
	
	public void listenerRefresh()
	{
		listenerThread = new Thread(this.listener);
		listenerThread.start();
	}
}
